#include "../include/guafs.h"
#include "stdio.h"

// 驱动读
int guafs_driver_read(int offset, uint8_t *out_content, int size) {
    int      offset_aligned = ROUND_DOWN(offset, BLOCK_SIZE);
    int      bias           = offset - offset_aligned;
    int      size_aligned   = ROUND_UP((size + bias), BLOCK_SIZE);
    uint8_t* temp_content   = (uint8_t*)malloc(size_aligned);
    uint8_t* cur            = temp_content;
    ddriver_seek(super.fd, offset_aligned, SEEK_SET);
    while (size_aligned != 0)
    {
        // 要分两次进行IO读入一个块
        ddriver_read(super.fd, cur, IO_SIZE);
        ddriver_read(super.fd, cur+IO_SIZE, IO_SIZE);
        cur          += BLOCK_SIZE;
        size_aligned -= BLOCK_SIZE;   
    }
    memcpy(out_content, temp_content + bias, size);
    free(temp_content);
    return 0;
}

int guafs_driver_write(int offset, uint8_t *in_content, int size) {
    int      offset_aligned = ROUND_DOWN(offset, BLOCK_SIZE);
    int      bias           = offset - offset_aligned;
    int      size_aligned   = ROUND_UP((size + bias), BLOCK_SIZE);
    uint8_t* temp_content   = (uint8_t*)malloc(size_aligned);
    uint8_t* cur            = temp_content;
    guafs_driver_read(offset_aligned, temp_content, size_aligned);
    memcpy(temp_content + bias, in_content, size);
    
    ddriver_seek(super.fd, offset_aligned, SEEK_SET);
    while (size_aligned != 0)
    {
        ddriver_write(super.fd, cur, IO_SIZE);
        ddriver_write(super.fd, cur+IO_SIZE, IO_SIZE);
        cur          += BLOCK_SIZE;
        size_aligned -= BLOCK_SIZE;   
    }

    free(temp_content);
    return 0;
}

struct guafs_inode* guafs_alloc_inode(struct guafs_dentry * dentry) {
    super.cur_inode_num++;
    if (super.cur_inode_num>3)
    {
        // perror("inode num more than 2");
        return NULL;
    }
    
    struct guafs_inode* inode;
    int byte_cursor = 0; 
    int bit_cursor  = 0; 
    int ino_cursor  = 0;
    int is_find_free_entry = 0;
    
    // 设置对应的inode位图
    // 按字节跳动
    for (byte_cursor = 0; byte_cursor < BLKS_SZ(super.map_inode_blks); 
         byte_cursor++)
    {
        // 一个Byte的位图里的位处理
        for (bit_cursor = 0; bit_cursor < UINT8_BITS; bit_cursor++) {
            if((super.inode_map[byte_cursor] & (0x1 << bit_cursor)) == 0) {    
                                                      /* 当前ino_cursor位置空闲 */
                super.inode_map[byte_cursor] |= (0x1 << bit_cursor);
                is_find_free_entry = 1;           
                break;
            }
            ino_cursor++;
        }
        if (is_find_free_entry) {
            break;
        }
    }

    if (!is_find_free_entry || ino_cursor >= super.max_ino)
    {
        perror("error in alloc inode no more inode");
        return NULL;
    }

    inode = (struct guafs_inode*)malloc(sizeof(struct guafs_inode));
    inode->ino  = ino_cursor; 
    inode->size = 0;
                                                      /* dentry指向inode */
    dentry->inode = inode;
    dentry->ino   = inode->ino;
                                                      /* inode指回dentry */
    inode->my_dentry = dentry;
    
    inode->dir_cnt = 0;
    inode->child_dentrys = NULL;
    inode->ftype=dentry->ftype;
    memset(inode->datablk_pointer, 0, DATA_BLOCK_NUM);
    // 修改成无论是文件夹还是文件都事先分配好6个块
    guafs_alloc_dataPointers(inode);
    // if (inode->ftype==REG_FILE) {
    //     guafs_alloc_dataPointers(inode);
    // }

    return inode;
}

// 给inode中的dataPointer分配数据块
int guafs_alloc_dataPointers(struct guafs_inode* inode)
{
    int byte_cursor=0;
    int bit_cursor=0;
    int dataBlk_cursor=0;
    for (int i = 0; i < DATA_BLOCK_NUM; i++)
    {
        if ((dataBlk_cursor=findFreeDataBlock())!=-1)
        {
            inode->datablk_pointer[i]=dataBlk_cursor;
        }
        else
        {
            return -1;
        }
    }
    return 1;
}


// 在super块的data_map位图中找到空闲块
// 若找到，返回该块的位置
// 若找不到，返回-1
int findFreeDataBlock()
{
    int is_find_free_entry=0;
    int byte_cursor=0;
    int bit_cursor=0;
    int dataBlk_cursor=0;
    for (byte_cursor = 0; byte_cursor < BLKS_SZ(super.map_data_blks); 
         byte_cursor++)
    {
        // 一个Byte的位图里的位处理
        for (bit_cursor = 0; bit_cursor < UINT8_BITS; bit_cursor++) {
            if((super.data_map[byte_cursor] & (0x1 << bit_cursor)) == 0) {    
                                                      /* 当前dataBlk_cursor位置空闲 */
                super.data_map[byte_cursor] |= (0x1 << bit_cursor);
                is_find_free_entry = 1;           
                break;
            }
            dataBlk_cursor++;
        }
        if (is_find_free_entry) {
            break;
        }
    }
    if (is_find_free_entry)
    {
        return dataBlk_cursor;
    }
    else
    {
        return -1;
    }
}

// 将内存数据刷回磁盘
int guafs_sync_inode(struct guafs_inode * inode)
{
    struct guafs_inode_d  inode_d;
    struct guafs_dentry*  dentry_cursor;
    struct guafs_dentry_d dentry_d;
    int ino             = inode->ino;
    // 将inode结构在内存中的数据读进一个硬盘的Inode_d中，然后写入磁盘
    inode_d.ino         = ino;
    inode_d.size        = inode->size;
    inode_d.ftype       = inode->ftype;
    inode_d.dir_cnt     = inode->dir_cnt;
    for (int i = 0; i < DATA_BLOCK_NUM; i++)
    {
        inode_d.datablk_pointer[i]=inode->datablk_pointer[i];
    }
    
    int offset;

    // 写入inode
    if (guafs_driver_write(GUAFS_INO_OFS(ino), (uint8_t *)&inode_d, sizeof(struct guafs_inode_d)) != 0 ) 
    {
        perror("error in sync writeBack inode");
        return -EIO;
    }

    // 文件夹，数据按dentry写入
    if (inode->ftype == DIR) {      
        int dataBLKno=0;                    
        dentry_cursor = inode->child_dentrys;
        offset        = GUAFS_DATA_OFS(inode->datablk_pointer[dataBLKno]);
        while (dentry_cursor != NULL)
        {
            memcpy(dentry_d.fname, dentry_cursor->fname, MAX_NAME_LEN);
            dentry_d.ftype = dentry_cursor->ftype;
            dentry_d.ino = dentry_cursor->ino;
            dentry_d.valid = dentry_cursor->valid;
            // 将当前的dentry_d写入磁盘
            if (guafs_driver_write(offset, (uint8_t *)&dentry_d, 
                                 sizeof(struct guafs_dentry_d)) != 0) {
                perror("error in sync writeBack dentry");
                return -EIO;                     
            }
            // 递归同步子文件夹
            if (dentry_cursor->inode != NULL) {
                guafs_sync_inode(dentry_cursor->inode);
            }

            dentry_cursor = dentry_cursor->brother;
            // 在写同一个inode data里的dentry项，相邻写入即可
            offset += sizeof(struct guafs_dentry_d);
            // 当前块写完，需要写下一个块
            // 判断条件是下一次写完的地址越出当前块的尾界,代表当前块已经装不下下一个块了
            if (offset+sizeof(struct guafs_dentry_d)>GUAFS_DATA_OFS(inode->datablk_pointer[dataBLKno])+BLOCK_SIZE)
            {
                dataBLKno++;
                offset=GUAFS_DATA_OFS(inode->datablk_pointer[dataBLKno]);
            }
            
        }
    }
}

struct guafs_inode* guafs_read_inode(struct guafs_dentry * dentry, int ino)
    {
    struct guafs_inode* inode = (struct guafs_inode*)malloc(sizeof(struct guafs_inode));
    struct guafs_inode_d inode_d;
    struct guafs_dentry* sub_dentry;
    struct guafs_dentry_d dentry_d;
    int    dir_cnt = 0;
    // 与驱动交互的数据结构必须是_d的形式
    if (guafs_driver_read(GUAFS_INO_OFS(ino), (uint8_t *)&inode_d, 
                        sizeof(struct guafs_inode_d)) != 0) {
        perror("error in read_inode reading inode_d");
        return NULL;                    
    }
    inode->dir_cnt = 0;
    inode->ino = inode_d.ino;
    inode->size = inode_d.size;
    inode->ftype = inode_d.ftype;
    inode->my_dentry = dentry;
    inode->child_dentrys = NULL;
    for (int i = 0; i < DATA_BLOCK_NUM; i++)
    {
        inode->datablk_pointer[i]=inode_d.datablk_pointer[i];
    }
    // 文件夹类型inode按dentry读入data，组织好该inode的dentry项
    if (inode->ftype == DIR) {
        dir_cnt = inode_d.dir_cnt;
        int dataBLKno=0;
        int offset=GUAFS_DATA_OFS(inode->datablk_pointer[dataBLKno]);
        for (int i = 0; i < dir_cnt; i++)
        {
            if (guafs_driver_read(offset, 
                                (uint8_t *)&dentry_d, 
                                sizeof(struct guafs_dentry_d)) != 0) {
                perror("error in read_inode reading dentry");
                return NULL;                    
            }
            sub_dentry = new_dentry(dentry_d.fname, dentry_d.ftype);
            sub_dentry->parent = inode->my_dentry;
            // inode的具体数据没有读入内存，可以在需要时根据dentry的ino号使用函数read_inode读入
            sub_dentry->ino    = dentry_d.ino; 
            // dentry插入文件夹inode中
            guafs_alloc_dentry(inode, sub_dentry);
            offset+=sizeof(struct guafs_dentry_d);
            if (offset+sizeof(struct guafs_dentry_d)>GUAFS_DATA_OFS(inode->datablk_pointer[dataBLKno])+BLOCK_SIZE)
            {
                dataBLKno++;
                // offset+=GUAFS_DATA_OFS(inode->datablk_pointer[dataBLKno]);
                offset=GUAFS_DATA_OFS(inode->datablk_pointer[dataBLKno]);
            }
            
        }
    }
    // 普通文件暂时不用读入内存，已经标记了该inode的6个数据块在硬盘中的位置
    // 在内存中存储每个文件6K的大小太多，暂时没设计内存存储inode数据的结构
    else if (inode->ftype == REG_FILE) {
    }
    return inode;
}

int guafs_alloc_dentry(struct guafs_inode* inode, struct guafs_dentry* dentry) {
    if (inode->child_dentrys == NULL) {
        inode->child_dentrys = dentry;
    }
    // 头插
    else {
        dentry->brother = inode->child_dentrys;
        inode->child_dentrys = dentry;
    }
    inode->dir_cnt++;
    return inode->dir_cnt;
} 

    
void guafs_dump_map() 
{
    int count=0;
    int byte_cursor = 0;
    int bit_cursor = 0;
    printf("\ninode_map\n");
    for (byte_cursor = 0; byte_cursor < BLKS_SZ(super.map_inode_blks); 
            byte_cursor+=4)
    {
        for (bit_cursor = 0; bit_cursor < UINT8_BITS; bit_cursor++) {
            printf("%d ", (super.inode_map[byte_cursor] & (0x1 << bit_cursor)) >> bit_cursor);   
        }
        printf("\t");

        for (bit_cursor = 0; bit_cursor < UINT8_BITS; bit_cursor++) {
            printf("%d ", (super.inode_map[byte_cursor + 1] & (0x1 << bit_cursor)) >> bit_cursor);   
        }
        printf("\t");
        
        for (bit_cursor = 0; bit_cursor < UINT8_BITS; bit_cursor++) {
            printf("%d ", (super.inode_map[byte_cursor + 2] & (0x1 << bit_cursor)) >> bit_cursor);   
        }
        printf("\t");
        
        for (bit_cursor = 0; bit_cursor < UINT8_BITS; bit_cursor++) {
            printf("%d ", (super.inode_map[byte_cursor + 3] & (0x1 << bit_cursor)) >> bit_cursor);   
        }
        printf("\n");
        count+=32;
        if (count>1000)
        {
            break;
        }
    }
    count=0;
    printf("\ndata map\n");
    for (byte_cursor = 0; byte_cursor < BLKS_SZ(super.map_data_blks); 
            byte_cursor+=4)
    {
        for (bit_cursor = 0; bit_cursor < UINT8_BITS; bit_cursor++) {
            printf("%d ", (super.data_map[byte_cursor] & (0x1 << bit_cursor)) >> bit_cursor);   
        }
        printf("\t");

        for (bit_cursor = 0; bit_cursor < UINT8_BITS; bit_cursor++) {
            printf("%d ", (super.data_map[byte_cursor + 1] & (0x1 << bit_cursor)) >> bit_cursor);   
        }
        printf("\t");
        
        for (bit_cursor = 0; bit_cursor < UINT8_BITS; bit_cursor++) {
            printf("%d ", (super.data_map[byte_cursor + 2] & (0x1 << bit_cursor)) >> bit_cursor);   
        }
        printf("\t");
        
        for (bit_cursor = 0; bit_cursor < UINT8_BITS; bit_cursor++) {
            printf("%d ", (super.data_map[byte_cursor + 3] & (0x1 << bit_cursor)) >> bit_cursor);   
        }
        printf("\n");
        count+=32;
        if (count>1000)
        {
            break;
        }
    }
}


// 使用路径找到文件的目录项 同时会将路径上的目录项读入内存中
struct guafs_dentry* guafs_lookup(const char * path, int* is_find, int* is_root) {
    struct guafs_dentry* dentry_cursor = super.root_dentry;
    struct guafs_dentry* dentry_ret = NULL;
    struct guafs_inode*  inode; 
    int   total_lvl = guafs_calc_lvl(path);
    int   lvl = 0;
    int is_hit;
    char* fname = NULL;
    char* path_cpy = (char*)malloc(sizeof(path));
    *is_root = 0;
    strcpy(path_cpy, path);

    if (total_lvl == 0) {                           /* 根目录 */
        *is_find = 1;
        *is_root = 1;
        dentry_ret = super.root_dentry;
    }
    fname = strtok(path_cpy, "/");       
    while (fname)
    {   
        lvl++;
        if (dentry_cursor->inode == NULL) {           /* Cache机制 */
            guafs_read_inode(dentry_cursor, dentry_cursor->ino);
        }

        inode = dentry_cursor->inode;
        // 中间路径应该都是文件夹，如果不是就报错
        if ((inode->ftype==REG_FILE) && lvl < total_lvl) {
            perror("middle path is not a DIR");
            dentry_ret = inode->my_dentry;
            break;
        }
        // dentry_cursor开始遍历inode的子文件项
        if ((inode->ftype==DIR)) {
            dentry_cursor = inode->child_dentrys;
            is_hit        = 0;
            // 在当级目录下寻找下一级的文件名（如果是最后一级就是找普通文件，如果不是则找目录文件）
            while (dentry_cursor)
            {
                if (memcmp(dentry_cursor->fname, fname, strlen(fname)) == 0) {
                    is_hit = 1;
                    break;
                }
                dentry_cursor = dentry_cursor->brother;
            }
            // 该级不存在，报错
            if (!is_hit) {
                *is_find = 0;
                perror("middle DIR does not exists");
                dentry_ret = inode->my_dentry;
                break;
            }
            // 找到了最后一级且存在，将最后一级的dentry赋值dentry_ret
            if (is_hit && lvl == total_lvl) {
                *is_find = 1;
                dentry_ret = dentry_cursor;
                break;
            }
        }
        fname = strtok(NULL, "/"); 
    }
    // 在错误的时候返回找不到路径的上级文件夹？
    if (dentry_ret->inode == NULL) {
        dentry_ret->inode = guafs_read_inode(dentry_ret, dentry_ret->ino);
    }
    
    return dentry_ret;
}

// 计算路径的层级
int guafs_calc_lvl(const char * path) {
    // char* path_cpy = (char *)malloc(strlen(path));
    // strcpy(path_cpy, path);
    char* str = path;
    int   lvl = 0;
    if (strcmp(path, "/") == 0) {
        return lvl;
    }
    while (*str != NULL) {
        if (*str == '/') {
            lvl++;
        }
        str++;
    }
    return lvl;
}

char* guafs_get_fname(const char* path) {
    char ch = '/';
    char *q = strrchr(path, ch) + 1;
    return q;
}

// 将inode的第dir个目录项取出
struct guafs_dentry* guafs_get_dentry(struct guafs_inode * inode, int dir) {
    struct guafs_dentry* dentry_cursor = inode->child_dentrys;
    int    cnt = 0;
    while (dentry_cursor)
    {
        if (dir == cnt) {
            return dentry_cursor;
        }
        cnt++;
        dentry_cursor = dentry_cursor->brother;
    }
    return NULL;
}